﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AnguaRPGEngine.DND4eModule.Forms;
using AnguaRPGEngine.Library.Configuration;
using AnguaRPGEngine.Library.Forms;
using AnguaRPGEngine.Library.Interfaces;
using AnguaRPGEngine.Library.Packages;
using AnguaRPGEngine.Library.Parts;
using AnguaRPGEngine.Library.Systems;

namespace AnguaRPGEngine.DND4eModule
{
    [Export(typeof(IARPGEModule))]
    [ExportMetadata("ID", "2C21A7EF-ADA7-48CE-96BB-5C5311517E96")]
    public class DND4e : IARPGEModule
    {
        private DNDGame _Game;
        private List<RuleBook> _RuleBooks;
        private List<DNDPlayerCharacter> _PlayerCharacters; // this is the list for the GM
        private DNDPlayerCharacter _PlayerCharacter; // this is either the player's PC or the current selected on for the GM
        private List<IPart> _Counters;
        private GMPlayersForm _GMPlayersForm;
        #region IARPGEModule Members
        #region GameName
        public string GameName
        {
            get
            {
                if (_Game == null)
                {
                    return "None";
                }
                else
                {
                    return _Game.Name;
                }
            }
        }
        #endregion
        #region Counters
        public List<IPart> Counters
        {
            get
            {
                _Counters = Serializer<List<IPart>>.DeserializeFromFile(GameSystem.Instance.PathToData + "Images\\Parts\\Counter\\DnD4e\\Counters.dat");
                if (_Counters == null)
                {
                    GenerateTestCounters();
                }
                return _Counters;
            }
        }
        #endregion
        #region ID
        public Guid ID
        {
            get
            {
                return Guid.Parse("2C21A7EF-ADA7-48CE-96BB-5C5311517E96");
            }
        }
        #endregion
        public string Name
        {
            get { return "Dungeons & Dragons 4th Edition"; }
        }
        public bool GameIsLoaded
        {
            get { return _Game != null; }
        }

        public string Description
        {
            get { return "This MMalo M.U.S.H. Module allows you to play through adventures and campaigns using the 4th edition rules."; }
        }

        public bool ImportCharacter(string FileSpec)
        {
            bool Success = false;
            CharacterBuilderImporter cbi = new CharacterBuilderImporter();
            _PlayerCharacter = cbi.Import(FileSpec);
            return Success;
        }
        public string AddCharacter(string SerializedCharacter)
        {
            string counterString = "";
            DNDPlayerCharacter playerCharacter = Serializer<DNDPlayerCharacter>.DeserializeFromString(SerializedCharacter);
            if (_GMPlayersForm != null)
            {
                _GMPlayersForm.UpdateCharacter(playerCharacter);
            }
            DNDPlayerCharacter pc = _PlayerCharacters.Find(p => p.CharacterName == playerCharacter.CharacterName);
            if (pc == null)
            {
                _PlayerCharacters.Add(playerCharacter);
                Counter counter = playerCharacter.GetCounter();
                Serializer<Counter>.SerializeToString(counter, out counterString);
            }
            else
            {
                pc.Update(playerCharacter);
                Counter counter = pc.GetCounter();
                Serializer<Counter>.SerializeToString(counter, out counterString);
            }
            return counterString;
        }
        public string UpdateCharacter(string SerializedCharacter)
        {
            string counterString = "";
            DNDPlayerCharacter playerCharacter = Serializer<DNDPlayerCharacter>.DeserializeFromString(SerializedCharacter);
            if (_GMPlayersForm != null)
            {
                _GMPlayersForm.UpdateCharacter(playerCharacter);
            }
            DNDPlayerCharacter pc = _PlayerCharacters.Find(p => p.CharacterName == playerCharacter.CharacterName);
            if (pc != null)
            {
                pc.Update(playerCharacter);
                Counter counter = pc.GetCounter();
                Serializer<Counter>.SerializeToString(counter, out counterString);
            }
            return counterString;
        }
        public Form GetPlayersForGM(Form parent)
        {
            _GMPlayersForm = new GMPlayersForm(_PlayerCharacters, parent);
            return _GMPlayersForm;
        }

        public Form GetPlayerForPC(Form parent)
        {
            return new PCPlayerForm(_PlayerCharacter, parent);
        }
        public string FileFilter
        {
            get
            {
                return "Game Files (*.dnd4eg)|*.dnd4eg";
            }
        }
        public void SetRulesMenu(ref ToolStripMenuItem tsmiRules)
        {
            CreateRulesMenu(ref tsmiRules);
        }
        public MapFileClass GetCurrentMap()
        {
            try
            {
                return Serializer<MapFileClass>.DeserializeFromFile(_Game.Areas[_Game.CurrentArea].AreaMapFileSpec);
            }
            catch
            {
            }
            return null;
        }
        void CreateRulesMenu(ref ToolStripMenuItem tsmiRules)
        {
            tsmiRules.DropDownItems.Clear();
            if (File.Exists(GameSystem.Instance.PathToDLLs + string.Format("RuleBooks4{0}.dat", GameSystem.Instance.IsGMClient ? "GM" : "PC")))
            {
                _RuleBooks = Serializer<List<RuleBook>>.DeserializeFromFile(GameSystem.Instance.PathToDLLs + string.Format("RuleBooks4{0}.dat", GameSystem.Instance.IsGMClient ? "GM" : "PC"));
                foreach (RuleBook book in _RuleBooks)
                {
                    ToolStripMenuItem tsmiBook = new ToolStripMenuItem(book.BookName);
                    ToolStripMenuItem tsmiWholeBook = new ToolStripMenuItem("Open " + book.BookName);
                    tsmiWholeBook.Click += new EventHandler(BookMenu_Click);
                    tsmiBook.DropDownItems.Add(tsmiWholeBook);
                    tsmiBook.DropDownItems.Add(new ToolStripSeparator());
                    foreach (Bookmark mark in book.Bookmarks)
                    {
                        ToolStripMenuItem tsmiMark = new ToolStripMenuItem(string.Format("{0}  (Pg.{1})", mark.Name, mark.Page));
                        tsmiMark.Click += new EventHandler(BookMenu_Click);
                        tsmiBook.DropDownItems.Add(tsmiMark);
                    }
                    tsmiRules.DropDownItems.Add(tsmiBook);

                }
            }
        }

        void BookMenu_Click(object sender, EventArgs e)
        {
            string book = ((ToolStripMenuItem)sender).Text;
            string mark = "";
            if (!book.StartsWith("Open"))
            {
                book = ((ToolStripMenuItem)sender).OwnerItem.Text;
                mark = ((ToolStripMenuItem)sender).Text;

            }
            book = book.Replace("Open ", "");


            RuleBook rb = _RuleBooks.Find(p => p.BookName == book);
            string bookFSPec = rb.FileName;
            string fSpec = "";
            if (mark.Length > 0)
            {
                fSpec = rb.Bookmarks.Find(p => mark.StartsWith(p.Name)).OpenCommand;
                bookFSPec = fSpec.Substring(0, fSpec.IndexOf(".exe") + 4);
                fSpec = fSpec.Remove(0, fSpec.IndexOf(".exe") + 4);
            }
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = bookFSPec;
            proc.StartInfo.Arguments = fSpec;
            proc.Start();
        }
        #region New, Load, Save Character
        public void SaveCharacter()
        {
        }
        public void SaveCharacter(bool saveAs)
        {
        }
        private void SaveCharacterAs()
        {
            using (SaveFileDialog sfd = new SaveFileDialog())
            {
                sfd.Title = string.Format("Save {0} Player Character", Name);
                sfd.Filter = FileFilter;
                sfd.InitialDirectory = string.Format("{0}Characters\\DND4e\\", GameSystem.Instance.PathToData);
                if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    Serializer<DNDPlayerCharacter>.SerializeToFile(_PlayerCharacter, sfd.FileName);
                }
            }
        }
        public void NewCharacter(Form parent)
        {
        }
        public void LoadCharacter()
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.Title = string.Format("Load {0} Player Character", Name);
                ofd.Filter = FileFilter;
                ofd.InitialDirectory = string.Format("{0}Characters\\DND4e\\", GameSystem.Instance.PathToData);
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    _PlayerCharacter = Serializer<DNDPlayerCharacter>.DeserializeFromFile(ofd.FileName);
                }
            }
        }
        #endregion
        #region New, Load, Save Game
        public void SaveGame()
        {
        }
        public void SaveGame(bool saveAs)
        {
        }
        private void SaveGameAs()
        {
            using (SaveFileDialog sfd = new SaveFileDialog())
            {
                sfd.Title = string.Format("Save {0} Game", Name);
                sfd.Filter = FileFilter;
                sfd.InitialDirectory = string.Format("{0}Games\\DND4e\\", GameSystem.Instance.PathToData);
                if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    Serializer<DNDGame>.SerializeToFile(_Game, sfd.FileName);
                }
            }
        }
        public void NewGame(Form parent)
        {
            using (DNDGameEditor geForm = new DNDGameEditor(null))
            {
                if (geForm.ShowDialog() == DialogResult.OK)
                {
                    _Game = geForm.Game;
                    string path = string.Format("{0}Games\\DND4e\\", GameSystem.Instance.PathToData);
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    string gameFSpec = string.Format("{0}{1}.dnd4eg", path, _Game.Name);
                    if (Serializer<DNDGame>.SerializeToFile(_Game, gameFSpec))
                    {
                        MessageBox.Show(parent, string.Format("Successfully saved game \"{0}\".", gameFSpec), "Game Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    else
                    {

                        MessageBox.Show(parent, Serializer<DNDGame>.ErrorMessage, "Error Saving Game", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
            }
        }
        public void EditGame(Form parent)
        {
            using (DNDGameEditor geForm = new DNDGameEditor(_Game))
            {
                if (geForm.ShowDialog() == DialogResult.OK)
                {
                    _Game = geForm.Game;
                    string path = string.Format("{0}Games\\DND4e\\", GameSystem.Instance.PathToData);
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    string gameFSpec = string.Format("{0}{1}.dnd4eg", path, _Game.Name);
                    if (Serializer<DNDGame>.SerializeToFile(_Game, gameFSpec))
                    {
                        MessageBox.Show(parent, string.Format("Successfully saved game \"{0}\".", gameFSpec), "Game Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    else
                    {

                        MessageBox.Show(parent, Serializer<DNDGame>.ErrorMessage, "Error Saving Game", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
            }
        }
        public void LoadGame()
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.Title = string.Format("Load {0} Game", Name);
                ofd.Filter = FileFilter;
                ofd.InitialDirectory = string.Format("{0}Games\\DND4e\\", GameSystem.Instance.PathToData);
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    _Game = Serializer<DNDGame>.DeserializeFromFile(ofd.FileName);
                }
            }
        }
        #endregion
        public DialogResult EditBooks()
        {
            using (BookListForm blf = new BookListForm(_RuleBooks))
            {
                if (blf.ShowDialog() == DialogResult.OK)
                {
                    _RuleBooks = blf.Books;
                    Serializer<List<RuleBook>>.SerializeToFile(_RuleBooks, GameSystem.Instance.PathToDLLs + string.Format("RuleBooks4{0}.dat", GameSystem.Instance.IsGMClient ? "GM" : "PC"));
                    return DialogResult.OK;
                }
            }
            return DialogResult.None;
        }
        public void ProcessPackage(BufferPackage package)
        {
        }

        public bool PlayerAllowed(Guid PlayerGuid)
        {
            return _Game.Players.FindAll(p => p.PlayerInfo.ID == PlayerGuid).Count > 0;
        }

        public bool GameAllowed(Guid GameGuid)
        {
            return _Game.ID == GameGuid;
        }
        public bool PasswordMatch(string Password)
        {
            return _Game.Password == Password;
        }

        #endregion
        private Counter GetTestCounter(int counterID)
        {
            Counter counter = new Counter();
            switch (counterID)
            {
                case 0:
                    counter.ImageName = "Parts.Counter.DnD4e.DecrepitSkeleton001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Decrepit Skeleton";
                    counter.Keywords = "D&D Monster Undead Decrepit Skeleton";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 1:
                    counter.ImageName = "Parts.Counter.DnD4e.DireRat001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Dire Rat";
                    counter.Keywords = "D&D Monster Vermin Dire Rat";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 2:
                    counter.ImageName = "Parts.Counter.DnD4e.ElfArcher001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Elf Archer";
                    counter.Keywords = "D&D Monster Elf Archer";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 3:
                    counter.ImageName = "Parts.Counter.DnD4e.ElfScout001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Elf Scout";
                    counter.Keywords = "D&D Monster Elf Scout";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 4:
                    counter.ImageName = "Parts.Counter.DnD4e.FireBeetle001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Fire Beetle";
                    counter.Keywords = "D&D Monster Insect Fire Beetle";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 5:
                    counter.ImageName = "Parts.Counter.DnD4e.GiantRat001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Giant Rat";
                    counter.Keywords = "D&D Monster Vermin Giant Rat";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 6:
                    counter.ImageName = "Parts.Counter.DnD4e.GnomeSkulk001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Gnome Skulk";
                    counter.Keywords = "D&D Monster Gnome Skulk";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 7:
                    counter.ImageName = "Parts.Counter.DnD4e.GoblinBlackblade001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Goblin Blackblade";
                    counter.Keywords = "D&D Monster Goblin Blackblade";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 8:
                    counter.ImageName = "Parts.Counter.DnD4e.GoblinCutter001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Goblin Cutter";
                    counter.Keywords = "D&D Monster Goblin Cutter";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 9:
                    counter.ImageName = "Parts.Counter.DnD4e.GoblinSharpshooter001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Goblin Sharpshooter";
                    counter.Keywords = "D&D Monster Goblin Sharpshooter";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 10:
                    counter.ImageName = "Parts.Counter.DnD4e.GoblinWarrior001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Goblin Warrior";
                    counter.Keywords = "MD&D Monster Goblin Warrior";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 11:
                    counter.ImageName = "Parts.Counter.DnD4e.GrayWolf001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Gray Wolf";
                    counter.Keywords = "D&D Monster Canine Gray Wolf";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 12:
                    counter.ImageName = "Parts.Counter.DnD4e.GuardDrake001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Guard Drake";
                    counter.Keywords = "D&D Monster Guard Drake";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(45, 45);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
                case 13:
                    counter.ImageName = "Parts.Counter.DnD4e.HalflingScout001";
                    counter.Location = new Point(0, 0);
                    counter.Name = "Halfling Scount";
                    counter.Keywords = "D&D Monster Halfling Scout";
                    counter.CounterID = "";
                    counter.IDLocation = new Point(34, 35);
                    counter.PlayerID = new Guid();
                    counter.Rotation = 0;
                    counter.Size = new Size(1, 1);
                    counter.VisibleToPlayers = true;
                    break;
            }
 
            return counter;
        }
        private void GenerateTestCounters()
        {
            _Counters = new List<IPart>();
            for (int c = 0; c < 14; c++)
            {
                _Counters.Add(GetTestCounter(c));
            }
        }
    }
}